package com.getword.service.impl;

import com.getword.domain.Course;
import com.getword.domain.Outline;
import com.getword.domain.OutlineDetail;
import com.getword.domain.User;
import com.getword.mongodao.CourseRepository;
import com.getword.mongodao.OutlineDetailRepository;
import com.getword.mongodao.OutlineRepository;
import com.getword.service.OutlineService;
import com.getword.utils.POIUtils;
import com.getword.utils.PathUtil;
import com.getword.web.model.FileInfo;
import com.getword.web.model.Result;
import com.getword.web.model.ResultCode;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.mongodb.client.result.UpdateResult;
import org.apache.commons.lang.StringUtils;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

@Service
//@Transactional(readOnly = false, isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED)
public class OutlineServiceImpl implements OutlineService {
    //    @Autowired
//    private OutlineDao outlineDao;
    @Autowired
    private OutlineRepository outlineRepository;
    @Autowired
    private OutlineDetailRepository outlineDetailRepository;
    @Autowired
    private MongoTemplate mongo;

    // 获得SpringBoot提供的mongodb的GridFS对象
    @Autowired
    private GridFsTemplate gridFsTemplate;
    @Autowired
    private GridFSBucket gridFSBucket;
    @Autowired
    private CourseRepository courseRepository;


    @Override
    public Result getChild(Long pid) {
        if(pid<0){
            return Result.fail(ResultCode.PARAM_IS_INVALID.getCode(), "参数不合法", null);
        }
//        List<Outline> outlines = outlineDao.selectByPid(pid);

        return Result.success(null, null);
    }

    @Override
    public Result saveOutline(Outline outline, HttpServletRequest request) {

        // 保存大纲
        List<Map<String, Object>> content = (List<Map<String, Object>>) request.getSession().getAttribute("outline");

        // 将content写入临时文件，等待保存到数据库
        String tmpPath = PathUtil.basePath + "static/upload/outline/" + UUID.randomUUID().toString();
        InputStream inputStream = POIUtils.writeOutline(content, tmpPath);
        if(inputStream!=null){
            outline.setFilepath(tmpPath+".xlsx");
            // 获取文件,保存到数据库，原始文件
            FileInfo file = (FileInfo) request.getSession().getAttribute("file");
            ObjectId store = gridFsTemplate.store(inputStream, file.getFilename(), file.getContentType());
            outline.setFileId(store.toHexString());
        }else{
            // 获取文件,保存到数据库，原始文件
            FileInfo file = (FileInfo) request.getSession().getAttribute("file");
            ObjectId store = gridFsTemplate.store(file.getInputStream(), file.getFilename(), file.getContentType());
            outline.setFileId(store.toHexString());
        }



        outline.setContent(content);
        outline.setUploadTime(new Date());
        // grade属性
        Course course = courseRepository.findCourseById(outline.getCourse().getId());
        outline.setGrade(course.getGrade());
        outline.setStatus(false); // 未审核
        Outline save = outlineRepository.save(outline);


        // 大纲细节保存,不能使用for循环插入数据，容易产生id冲突
        List<OutlineDetail> details = new ArrayList<>();
        for(Map<String, Object> detail : content){
            OutlineDetail outlineDetail = new OutlineDetail();
            outlineDetail.setName(detail.get("name").toString());
            outlineDetail.setOutlineId(save.getId());
            outlineDetail.setChapterId((Integer) detail.get("id"));
            outlineDetail.setNum(detail.get("num").toString());
            details.add(outlineDetail);
        }
        outlineDetailRepository.saveAll(details);

        request.getSession().removeAttribute("outline");
        return Result.success(save, null);
    }

    @Override
    public Result updateSessionOutline(Integer id, String name, String intro, HttpServletRequest request) {
        List<Map<String, Object>> content = (List<Map<String, Object>>) request.getSession().getAttribute("outline");
        for(Map<String,Object> c :content){
            if(c.get("id") == id){
                c.put("name", name);
                c.put("intro", intro);
                break;
            }
        }
        return Result.success("ok");
    }

    @Override
    public Result getOutlineData(MultipartFile file, HttpServletRequest request) {
        String[] split = StringUtils.split(file.getOriginalFilename(), ".");
        String ext = split[split.length-1];
        try {
            InputStream inputStream = file.getInputStream();
//            gridFsTemplate.store(inputStream, )
            List<Map<String, Object>> content = POIUtils.renderList(inputStream, ext);
            // 暂存到session中
            request.getSession().setAttribute("outline", content);
            FileInfo fileInfo = new FileInfo();
            fileInfo.setFilename(file.getOriginalFilename());
            fileInfo.setContentType(file.getContentType());
            fileInfo.setInputStream(file.getInputStream());
            request.getSession().setAttribute("file", fileInfo);
            return Result.success(content, null);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public Result checkName(Long courseId, String name) {
        Query query = Query.query(Criteria.where("name").regex(name, "i").and("course").is(new Course(courseId)));
        List<Outline> list = mongo.find(query, Outline.class);
        if(list==null||list.size()==0){
            return Result.success(new HashMap<String, Object>(){{
                put("exists", false);
            }}, null);
        }else{
            return Result.success(new HashMap<String, Object>(){{
                put("exists", true);
            }}, null);
        }
    }

    @Override
    public Result getOutlineByCourseId(Long courseId) {
        List<Outline> outlines = outlineRepository.findOutlineByCourse(new Course(courseId));
        return Result.success(outlines);
    }

    // 根据id获取大纲
    @Override
    public Result getOutlineById(Long id) {
        Outline outline = outlineRepository.findOutlineById(id);
        if(outline==null){
            return Result.fail("大纲不存在");
        }

        GridFSFile file = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(outline.getFileId())));
        GridFSDownloadStream in = gridFSBucket.openDownloadStream(file.getObjectId());

        GridFsResource resource = new GridFsResource(file,in);
        try {
            InputStream inputStream = resource.getInputStream();
            List<Map<String, Object>> content = POIUtils.renderJson(inputStream, PathUtil.getFileExt(file.getFilename()));
            System.out.println(content);
            return Result.success(content);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Result.fail("系统繁忙");
    }

    @Override
    public Result pass(Long id) {
        Query query = Query.query(Criteria.where("id").is(id));
        Update update = Update.update("status", true);
        UpdateResult result = mongo.updateFirst(query, update, Outline.class);
        if(result.getModifiedCount()>0){
            return Result.success(result);
        }
        return Result.fail("审核未通过");
    }

    @Override
    public Object getOutlinePage(Pageable page, Outline outline, Long userId) {
        Map<String, Object> result = new HashMap<>();
        outline.setUser(new User(userId));
        outline.setName("test");
        Criteria where = Criteria.where("user").is(new User(userId)).and("name").regex(".*"+ outline.getName() +".*");
        Query query = Query.query(where).skip(page.getOffset()).limit(page.getPageSize());
        List<Outline> outlines = mongo.find(query, Outline.class);
        long count = mongo.count(query, Outline.class);
        result.put("code", 0);
        result.put("data", outlines);
        result.put("count", count);

        return result;
    }

    @Override
    public Result demo() {
        Outline outline = mongo.findOne(new Query(), Outline.class);
        return Result.success(outline);
    }

    @Override
    public Object getOutlinePageAllLay(Pageable pageable, Outline outline) {
        Map<String, Object> result = new HashMap<>();
        outline.setName("test");
        Criteria where = Criteria.where("name").regex(".*"+ outline.getName() +".*");
        Query query = Query.query(where).skip(pageable.getOffset()).limit(pageable.getPageSize());
        List<Outline> outlines = mongo.find(query, Outline.class);
        long count = mongo.count(query, Outline.class);
        result.put("code", 0);
        result.put("data", outlines);
        result.put("count", count);
        return result;
    }

    @Override
    public Result getOutlinePageAll(Pageable pageable, Outline outline) {
        ExampleMatcher matcher = ExampleMatcher.matching() //构建对象
                .withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING) //改变默认字符串匹配方式：模糊查询
                .withIgnoreCase(true) //改变默认大小写忽略方式：忽略大小写
                .withMatcher("name", ExampleMatcher.GenericPropertyMatchers.contains())
                .withIgnorePaths("id"); //采用“包含匹配”的方式查询
        Example<Outline> example = Example.of(outline, matcher);
        Page<Outline> all = outlineRepository.findAll(example, pageable);

        return Result.success(all);
    }

    @Override
    public Result allCount(Outline outline) {
        ExampleMatcher matcher = ExampleMatcher.matching() //构建对象
                .withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING) //改变默认字符串匹配方式：模糊查询
                .withIgnoreCase(true) //改变默认大小写忽略方式：忽略大小写
                .withMatcher("name", ExampleMatcher.GenericPropertyMatchers.contains())
                .withIgnorePaths("id"); //采用“包含匹配”的方式查询
        Example<Outline> example = Example.of(outline, matcher);
        long count = outlineRepository.count(example);
        return Result.success(count);
    }

}
